﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Diagnostics;
using ThreeByte.ActiveDeck.Config;
using System.Reflection;

namespace ThreeByte.ActiveDeck.Data.UserResponse
{
    public abstract class AggregateUserData
    {
        protected static readonly XNamespace ns = Service.ServiceConfiguration.NAMESPACE;

        private static readonly Dictionary<string, Type> UserDataTypeLookup;

        static AggregateUserData() {
            UserDataTypeLookup = new Dictionary<string, Type>();

            //Collect UserData Types
            Assembly thisAssembly = Assembly.GetCallingAssembly();
            Type[] allTypes = thisAssembly.GetTypes();
            foreach(Type t in allTypes) {
                //Don't count the base
                if(!t.IsAbstract) {
                    //There exists some reference to this attribute
                    UserDataAttribute[] atts = (UserDataAttribute[])(t.GetCustomAttributes(typeof(UserDataAttribute), true));
                    if(atts.Length > 0) {
                        UserDataTypeLookup[atts.First().ShortTypeName] = t;  //This is a UserData object that we want to expose
                    }
                }
            }
        }

        public int Page {
            get;
            protected set;
        }

        public int TotalResponses {
            get;
            protected set;
        }

        protected AggregateUserData() {
            //TODO: Must remember to set the page value in the derived class
        }

        public AggregateUserData(int page) {
            Page = page;
        }

        public virtual XElement ToXml() {
            UserDataAttribute[] atts = (UserDataAttribute[])(this.GetType().GetCustomAttributes(typeof(UserDataAttribute), true));
            XElement node = new XElement(ns + "Aggregate", new XAttribute("Page", Page),
                                                            new XAttribute("TotalResponses", TotalResponses),
                                                            new XAttribute("Type", atts.First().ShortTypeName));

            return node;
        }

        public static AggregateUserData ParseXml(XElement node) {
            string typeString = node.Attribute("Type").Value;

            AggregateUserData userData = (AggregateUserData)(UserDataTypeLookup[typeString]
                                .GetMethod("ParseXml", BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly)
                                .Invoke(null, new object[] { node }));

            return userData;
        }


        //Update the Answer values and return true if anything changed
        public abstract bool UpdateUserData(AggregateUserData newUserData);

    }
}
